package com.starsea.book.model.webBook

import com.starsea.book.constant.PreferKey
import com.starsea.book.data.appDb
import com.starsea.book.data.entities.SearchBook
import com.starsea.book.help.config.AppConfig
import com.starsea.book.help.coroutine.CompositeCoroutine
import com.starsea.book.ui.book.search.SearchScope
import com.starsea.book.utils.getPrefBoolean
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.isActive
import splitties.init.appCtx

class SearchModel(private val scope: CoroutineScope, private val callBack: CallBack) {
    val threadCount = AppConfig.threadCount
//    private var searchPool: ExecutorCoroutineDispatcher? = null
    private var mSearchId = 0L
    private var searchPage = 1
    private var searchKey: String = ""
    private var tasks = CompositeCoroutine()
//    private var bookSourceList = arrayListOf<BookSource>()
    private var searchBooks = arrayListOf<SearchBook>()

    @Volatile
    private var searchIndex = -1

//    private fun initSearchPool() {
//        searchPool?.close()
//        searchPool = Executors
//            .newFixedThreadPool(min(threadCount, AppConst.MAX_THREAD)).asCoroutineDispatcher()
//    }

    fun search(searchId: Long, key: String) {
        callBack.onSearchStart()
        if (searchId != mSearchId) {
            if (key.isEmpty()) {
                callBack.onSearchCancel()
                return
            } else {
                this.searchKey = key
            }
            if (mSearchId != 0L) {
                close()
            }
//            initSearchPool()
            mSearchId = searchId
            searchPage = 1
//            bookSourceList.clear()
            searchBooks.clear()
            callBack.onSearchSuccess(searchBooks)
//            bookSourceList.addAll(callBack.getSearchScope().getBookSources())
//            if (bookSourceList.isEmpty()) {
//                callBack.onSearchCancel(NoStackTraceException("启用书源为空"))
//                return
//            }
        } else {
            searchPage++
        }
//        searchIndex = -1
//        for (i in 0 until threadCount) {
            search(searchId)
//        }
    }

    @Synchronized
    private fun search(searchId: Long) {

//        val map: MutableMap<String, String> = arrayMapOf()
//        map["newsType"] = newsType.toString()
//        map["pageNo"] = pageNo.toString()
//        map["pageSize"] = 10.toString()
//        val json = Gson().toJson(map)
//        execute {
//            okHttpClient.newCallResponseBody {
//                url(AppConst.BASE_URL.plus("front-api/notices/findNewsList"))
//                    .postJson(json)
//            }.text().let {
//                LogUtils.e(">>>", ">>.${it}")
//                val entity: BaseEntity<MsgListEntity> =
//                    it.gsonNormal(MsgListEntity::class.java)
//                msgListResult.postValue(entity)
//            }
//        }.onError {
//            context.toastOnUi(it.localizedMessage ?: "ERROR")
//        }



//        if (searchIndex >= bookSourceList.lastIndex) {
//            return
//        }
//        searchIndex++
//        val source = bookSourceList.getOrNull(searchIndex) ?: return
//        val searchPool = searchPool ?: return
//        val task = WebBook.searchBook(
//            scope,
//            source,
//            searchKey,
//            searchPage,
//            context = searchPool,
//            start = CoroutineStart.LAZY,
//            executeContext = searchPool
//        ).timeout(30000L)
//            .onSuccess {
//                ensureActive()
//                onSuccess(searchId, it)
//            }
//            .onFinally {
//                onFinally(searchId)
//            }
//        task.start()
//        tasks.add(task)
    }

    @Synchronized
    private fun onSuccess(searchId: Long, items: ArrayList<SearchBook>) {
        if (searchId == mSearchId) {
            appDb.searchBookDao.insert(*items.toTypedArray())
            val precision = appCtx.getPrefBoolean(PreferKey.precisionSearch)
            mergeItems(scope, items, precision)
            callBack.onSearchSuccess(searchBooks)
        }
    }

    @Synchronized
    private fun onFinally(searchId: Long) {
//        if (searchIndex < bookSourceList.lastIndex) {
//            search(searchId)
//        } else {
//            searchIndex++
//        }
//        if (searchIndex >= bookSourceList.lastIndex
//            + min(bookSourceList.size, threadCount)
//        ) {
//            callBack.onSearchFinish(searchBooks.isEmpty())
//        }
    }

    private fun mergeItems(scope: CoroutineScope, newDataS: List<SearchBook>, precision: Boolean) {
        if (newDataS.isNotEmpty()) {
            val copyData = ArrayList(searchBooks)
            val equalData = arrayListOf<SearchBook>()
            val containsData = arrayListOf<SearchBook>()
            val otherData = arrayListOf<SearchBook>()
            copyData.forEach {
                if (!scope.isActive) return
                if (it.name == searchKey || it.author == searchKey) {
                    equalData.add(it)
                } else if (it.name.contains(searchKey) || it.author.contains(searchKey)) {
                    containsData.add(it)
                } else {
                    otherData.add(it)
                }
            }
            newDataS.forEach { nBook ->
                if (!scope.isActive) return
                if (nBook.name == searchKey || nBook.author == searchKey) {
                    var hasSame = false
                    equalData.forEach { pBook ->
                        if (!scope.isActive) return
                        if (pBook.name == nBook.name && pBook.author == nBook.author) {
                            pBook.addOrigin(nBook.origin)
                            hasSame = true
                        }
                    }
                    if (!hasSame) {
                        equalData.add(nBook)
                    }
                } else if (nBook.name.contains(searchKey) || nBook.author.contains(searchKey)) {
                    var hasSame = false
                    containsData.forEach { pBook ->
                        if (!scope.isActive) return
                        if (pBook.name == nBook.name && pBook.author == nBook.author) {
                            pBook.addOrigin(nBook.origin)
                            hasSame = true
                        }
                    }
                    if (!hasSame) {
                        containsData.add(nBook)
                    }
                } else if (!precision) {
                    var hasSame = false
                    otherData.forEach { pBook ->
                        if (!scope.isActive) return
                        if (pBook.name == nBook.name && pBook.author == nBook.author) {
                            pBook.addOrigin(nBook.origin)
                            hasSame = true
                        }
                    }
                    if (!hasSame) {
                        otherData.add(nBook)
                    }
                }
            }
            if (!scope.isActive) return
            equalData.sortByDescending { it.origins.size }
            equalData.addAll(containsData.sortedByDescending { it.origins.size })
            if (!precision) {
                equalData.addAll(otherData)
            }
            if (!scope.isActive) return
            searchBooks = equalData
        }
    }

    fun cancelSearch() {
        close()
        callBack.onSearchCancel()
    }

    fun close() {
        tasks.clear()
//        searchPool?.close()
//        searchPool = null
        mSearchId = 0L
    }

    interface CallBack {
        fun getSearchScope(): SearchScope
        fun onSearchStart()
        fun onSearchSuccess(searchBooks: ArrayList<SearchBook>)
        fun onSearchFinish(isEmpty: Boolean)
        fun onSearchCancel(exception: Exception? = null)
    }

}